using MediatR;
using Microsoft.EntityFrameworkCore;
using RBAC.Domain.SmartHealthcare.Hosiptial;
using RBAC.ErrorCode;
using RBAC.Interstructrue;
using RBAC.Interstructrue.Base;
using SmartHealthcare.Write.Api.Application.Command.InpatientRegistry;
using SmartHealthcare.Write.Api.DTo;

namespace SmartHealthcare.Write.Api.Application.Handler.InpatientRegistry
{
    /// <summary>
    /// 出院结算处理器
    /// </summary>
    public class DischargeSettlementHandler : IRequestHandler<DischargeSettlementCommand, APIResult<DischargeSettlementResultDto>>
    {
        private readonly RBACDbContext _dbContext;
        private readonly IBaseRepository<InpatientRegistryModel> _inpatientRegistryRepository;
        private readonly IBaseRepository<HospitalBedModel> _hospitalBedRepository;
        private readonly ILogger<DischargeSettlementHandler> _logger;

        public DischargeSettlementHandler(
            RBACDbContext dbContext,
            IBaseRepository<InpatientRegistryModel> inpatientRegistryRepository,
            IBaseRepository<HospitalBedModel> hospitalBedRepository,
            ILogger<DischargeSettlementHandler> logger)
        {
            _dbContext = dbContext;
            _inpatientRegistryRepository = inpatientRegistryRepository;
            _hospitalBedRepository = hospitalBedRepository;
            _logger = logger;
        }

        /// <summary>
        /// 处理出院结算
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<APIResult<DischargeSettlementResultDto>> Handle(DischargeSettlementCommand request, CancellationToken cancellationToken)
        {
            var result = new APIResult<DischargeSettlementResultDto>();

            try
            {
                // 验证参数
                if (!request.IsValid())
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "参数验证失败，请检查病人卡号、姓名和住院登记ID";
                    return result;
                }

                _logger.LogInformation($"开始处理出院结算，病人卡号：{request.MedicalCard}，病人姓名：{request.PatientName}");

                // 查找住院登记记录
                var inpatientRegistry = await _dbContext.inpatientRegistries
                    .FirstOrDefaultAsync(x => x.Id == request.InpatientRegistryId 
                        && x.MedicalCard == request.MedicalCard 
                        && x.IsDeleted == false, cancellationToken);

                if (inpatientRegistry == null)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "未找到该病人的住院登记记录";
                    _logger.LogWarning($"未找到住院登记记录，ID：{request.InpatientRegistryId}，卡号：{request.MedicalCard}");
                    return result;
                }

                // 验证病人姓名是否匹配
                var patient = await _dbContext.patientLists
                    .FirstOrDefaultAsync(x => x.MedicalCard == request.MedicalCard 
                        && x.Name == request.PatientName 
                        && x.IsDeleted == false, cancellationToken);

                if (patient == null)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "病人卡号与姓名不匹配，请检查输入信息";
                    _logger.LogWarning($"病人卡号{request.MedicalCard}与姓名{request.PatientName}不匹配");
                    return result;
                }

                // 检查是否已经出院
                if (inpatientRegistry.Discharge_status)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "该病人已经出院，不能重复办理出院结算";
                    _logger.LogWarning($"病人{request.PatientName}(卡号：{request.MedicalCard})已经出院");
                    return result;
                }

                // 计算药品费用
                var medicineExpenses = await _dbContext.hospitalExpenses
                    .Where(x => x.MedicalCard == request.MedicalCard 
                        && x.ItemType == "药品" 
                        && x.IsDeleted == false)
                    .ToListAsync(cancellationToken);

                var medicineFee = medicineExpenses.Sum(x => x.TotalAmount);

                // 计算住院费用（按天计算，每天100元）
                var admissionTime = inpatientRegistry.AdmissionTime;
                var dischargeTime = DateTime.Now;
                var daysInHospital = (dischargeTime - admissionTime).Days + 1;
                var hospitalizationFee = daysInHospital * 100; // 每天100元

                // 计算总费用
                var totalFee = medicineFee + hospitalizationFee;

                // 获取预交金额
                var advancePayment = inpatientRegistry.AdvancePayment;

                // 计算待支付金额
                var pendingAmount = totalFee - advancePayment;

                // 生成结算单文件
                var settlementFilePath = await GenerateSettlementFile(request.PatientName, request.MedicalCard, 
                    medicineFee, hospitalizationFee, totalFee, advancePayment, pendingAmount, medicineExpenses);

                // 更新住院登记状态为已出院
                inpatientRegistry.Discharge_status = true;

                // 释放病床资源
                var hospitalBed = await _dbContext.HospitalBeds
                    .FirstOrDefaultAsync(x => x.HospitalBedId == inpatientRegistry.WardId 
                        && x.IsDeleted == false, cancellationToken);

                if (hospitalBed != null)
                {
                    hospitalBed.HospitalBedStatus = 0; // 设置为空闲状态
                    hospitalBed.CurrentMedicalCard = string.Empty;
                    _hospitalBedRepository.Update(hospitalBed);
                }

                // 保存住院登记更新
                _inpatientRegistryRepository.Update(inpatientRegistry);

                // 创建结算结果
                var settlementResult = new DischargeSettlementResultDto
                {
                    MedicalCard = request.MedicalCard,
                    PatientName = request.PatientName,
                    MedicineFee = medicineFee,
                    HospitalizationFee = hospitalizationFee,
                    TotalFee = totalFee,
                    AdvancePayment = advancePayment,
                    PendingAmount = pendingAmount,
                    SettlementImagePath = settlementFilePath,
                    DischargeTime = dischargeTime,
                    MedicineDetails = medicineExpenses.Select(x => new MedicineDetailDto
                    {
                        MedicineName = x.ItemName,
                        Specification = x.Specification,
                        UnitPrice = x.UnitPrice,
                        Quantity = x.Quantity,
                        TotalAmount = x.TotalAmount
                    }).ToList()
                };

                result.Data = settlementResult;
                result.Code = APIEnums.Success;
                result.Msg = $"出院结算成功，总费用：{totalFee}，预交金额：{advancePayment}，待支付金额：{pendingAmount}";

                _logger.LogInformation($"成功办理出院结算，病人{request.PatientName}(卡号：{request.MedicalCard})，总费用：{totalFee}，待支付金额：{pendingAmount}");
            }
            catch (Exception ex)
            {
                result.Code = APIEnums.Fail;
                result.Msg = "办理出院结算时发生异常";
                _logger.LogError(ex, $"办理出院结算时发生异常，病人卡号：{request.MedicalCard}，病人姓名：{request.PatientName}");
            }

            return result;
        }

        /// <summary>
        /// 生成结算单文件
        /// </summary>
        /// <param name="patientName"></param>
        /// <param name="medicalCard"></param>
        /// <param name="medicineFee"></param>
        /// <param name="hospitalizationFee"></param>
        /// <param name="totalFee"></param>
        /// <param name="advancePayment"></param>
        /// <param name="pendingAmount"></param>
        /// <param name="medicineExpenses"></param>
        /// <returns></returns>
        private async Task<string> GenerateSettlementFile(string patientName, string medicalCard, 
            decimal medicineFee, decimal hospitalizationFee, decimal totalFee, 
            decimal advancePayment, decimal pendingAmount, List<HospitalExpenseModel> medicineExpenses)
        {
            try
            {
                // 创建结算单内容
                var settlementContent = new List<string>
                {
                    "==========================================",
                    "              出院结算单",
                    "==========================================",
                    "",
                    $"病人姓名：{patientName}",
                    $"病人卡号：{medicalCard}",
                    $"出院时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss}",
                    "",
                    "费用明细：",
                    $"  药品费用：{medicineFee:C}",
                    $"  住院费用：{hospitalizationFee:C}",
                    "",
                    $"总费用：{totalFee:C}",
                    $"预交金额：{advancePayment:C}",
                    $"待支付金额：{pendingAmount:C}",
                    "",
                    "药品明细："
                };

                // 添加药品明细
                foreach (var medicine in medicineExpenses)
                {
                    settlementContent.Add($"  {medicine.ItemName} - {medicine.Specification} - {medicine.Quantity}×{medicine.UnitPrice:C} = {medicine.TotalAmount:C}");
                }

                settlementContent.Add("");
                settlementContent.Add("==========================================");

                // 保存文件
                var fileName = $"settlement_{medicalCard}_{DateTime.Now:yyyyMMddHHmmss}.txt";
                var filePath = Path.Combine("wwwroot", "settlements", fileName);
                
                // 确保目录存在
                var directory = Path.GetDirectoryName(filePath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory!);
                }

                await File.WriteAllLinesAsync(filePath, settlementContent);

                return $"/settlements/{fileName}";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成结算单文件时发生异常");
                return string.Empty;
            }
        }
    }
} 